<?php

/**
 * Maikuro Framework
 *
 * LICENSE:
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * The license is bundled with this package in the file LICENSE.txt.
 * You may also obtain a copy of the License at this URL:
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @copyright  Copyright (c) 2010, Jonathan Hedrén
 * @author     Jonathan Hedrén <jonathan.hedren@gmail.com>
 * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
 */

/**
 * @see Filters
 */
require_once 'Filters.php';

/**
 * @see Validators
 */
require_once 'Validators.php';

abstract class AbstractFormElement
{
    /**
     *
     */
    private $decorator;

    /**
     * @var boolean
     */
    private $disabled = false;

    /**
     * @var filters
     */
    protected $filters = array();

    /**
     * @var string
     */
    private $label;

    /**
     * @var string
     */
    protected $name;

    /**
     * @var boolean
     */
    protected $valid = true;

    /**
     * @var array
     */
    protected $validationMessages;

    /**
     * @var array
     */
    protected $validators = array();

    /**
     * @var mixed
     */
    protected $value;

    /**
     *
     * @param string $name
     * @param string $label
     * @param array $validators
     * @param array $filters
     */
    public function __construct($name, $label = null, $validators = null, $filters = null)
    {
        $this->name = $name;
        $this->label = $label;
        if (is_array($validators)) {
            $this->validators = $validators;
        }
        if (is_array($filters)) {
            $this->filters = $filters;
        }
        return $this;
    }

    /**
     *
     * @return string
     */
    public function __toString()
    {
        return $this->toString();
    }

    /**
     * Adds a filter.
     *
     * @param string $filter
     * @return AbstractFormElement
     */
    public function addFilter($filter)
    {
        $this->filters[] = $filter;
        return $this;
    }

    /**
     * Adds multiple filters.
     *
     * @param array $filters
     * @return AbstractFormElement
     */
    public function addFilters(array $filters)
    {
        $this->filters = array_merge($this->filters, $filters);
        return $this;
    }

    /**
     * Adds a validator.
     *
     * @param string $validator
     * @param array $params[optional]
     * @return AbstractFormElement
     */
    public function addValidator($validator, $params = array())
    {
        $this->validators[$validator] = $params;
        return $this;
    }

    /**
     * Returns the form decorator if any.
     *
     * @return IFormElementDecorator
     */
    public function getDecorator()
    {
        return $this->decorator;
    }

    /**
     * Returns the element name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
    
    /**
     * Returns the label of the element.
     *
     * @return string
     */
    public function getLabel()
    {
        return $this->label;
    }

    /**
     * Returns any valdation messages.
     *
     * @return null|array
     */
    public function getValidationMessages()
    {
        return $this->validationMessages;
    }

    /**
     * Returns the value of the element.
     *
     * @return mixed
     */
    public function getValue()
    {
            return $this->value;
    }

    /**
     * Checks whether the element is disabled or not.
     *
     * @return boolean
     */
    public function isDisabled()
    {
        return $this->disabled;
    }

    /**
     * Checks whether the element is valid or not.
     *
     * @return boolean
     */
    public function isValid()
    {
        return $this->validate();
    }

    /**
     * Sets a form decorator.
     *
     * @param IFormDecorator $decorator
     * @return AbstractFormElement
     */
    public function setDecorator(IFormDecorator $decorator)
    {
        $this->decorator = $decorator;
        return $this;
    }

    /**
     * Sets whether the element is disabled or not.
     *
     * @param boolean $disabled
     * @return AbstractFormElement
     */
    public function setDisabled($disabled = true)
    {
        $this->disabled = (bool) $disabled;
        return $this;
    }

    /**
     * Sets a label for the element.
     *
     * @param string $label
     * @return AbstractFormElement
     */
    public function setLabel($label)
    {
        $this->label = $label;
        return $this;
    }

    /**
     * Sets the element name.
     *
     * @param string $name
     * @return AbstractFormElement
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * Sets the element value after it has been filtered
     * by the added filters.
     *
     * @param mixed $value
     * @return AbstractFormElement
     */
    public function setValue($value)
    {
        foreach ($this->filters as $filter) {
            $value = Filters::$filter($value);
        }
        $this->value = $value;
        return $this;
    }

    /**
     *
     * @return string
     */
    public function toString()
    {
        if ($this->decorator == null) {
            return $this->name;
        } else {
            return $this->decorator->decorateFormElement($this);
        }
    }

    /**
     * Validates the element by iterating over the added validators.
     *
     * @return boolean
     */
    protected function validate()
    {
        foreach ($this->validators as $validator => $params) {
            if (is_integer($validator)) {
                $validator = $params;
                $params = null;
            }
            $this->valid = Validators::$validator($this->getValue(), $params);
        }
        if (!$this->valid) {
            $this->validationMessages = Validators::getMessages();
        }
        return $this->valid;
    }
}